#!/usr/bin/env bash

# Copyright 2020 Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -e
set -u
set -o pipefail

# $snippet test_fortio_httpbin_interaction.sh syntax="bash" outputis="text"
$ FORTIO_POD=$(kubectl get pods -n istio-io-circuitbreaker | grep fortio | awk '{ print $1 }')
$ kubectl -n istio-io-circuitbreaker exec {{ .inputTerminalFlag }} $FORTIO_POD -c fortio /usr/bin/fortio -- load -curl http://httpbin:8000/get
# $verify verifier="contains"
200 OK
# $endsnippet

function ruby_eval() {
  ruby -e "p $1"
}

# check_percentage_bounds take 4 arguments as input. It must be invoked as follows
#
# $ check_percentage_bounds <percentage-lower-bound-200> <percentage-upper-bound-200> \
#                           <percentage-upper-bound-503> <percentage-upper-bound-503>
#
# Percentage of requests with status 200 must be between "percentage-lower-bound-200" and
# "percentage-upper-bound-200" inclusive. Same for 503. If bounds are breached then the
# function exits with status 1
function check_percentage_bounds() {
  local lower_bounds=( ["200"]=${1:-"100"}  ["503"]=${3:-"0"} )
  local upper_bounds=( ["200"]=${2:-"100"}  ["503"]=${4:-"0"} )

  readarray -t code_lines < <(grep -E "^Code ([1-5][0-9]{2,}) : [0-9]+ \(([0-9\.]+) %\)$")
  
  for code_line in "${code_lines[@]}"; do
    local status_code=$(echo $code_line | cut -d' ' -f2)
    local percentage_req=$(echo $code_line | cut -d' ' -f5 | sed "s/[\(]//g")

    local status_lower_bound=${lower_bounds[$status_code]}
    local status_upper_bound=${upper_bounds[$status_code]}
  
    local is_lower_bound_breached=$(ruby_eval "$percentage_req < $status_lower_bound")
    local is_upper_bound_breached=$(ruby_eval "$percentage_req > $status_upper_bound")
 
    if [[ $is_lower_bound_breached == "true" || $is_upper_bound_breached == "true" ]]; then
      echo "either lower bound or upper bound is breached"
      echo "status=$status_code actual=$percentage_req, low=$status_lower_bound high=$status_upper_bound"
      exit 1
    fi
  done
}

function verify_circuit_breaking() {
  local fortio_output=`cat` # preserve output

  echo "$fortio_output" | check_percentage_bounds $1 $2 $3 $4
  if (($? != 0)); then
    exit 1;
  fi

  echo "$fortio_output"
}

# $snippet almost_trip_circuit_breaker.sh syntax="bash" outputis="text"
$ kubectl -n istio-io-circuitbreaker exec {{ .inputTerminalFlag }} $FORTIO_POD -c fortio /usr/bin/fortio -- \
    load -c 2 -qps 0 -n 20 -loglevel warning http://httpbin:8000/get {{ .beforeCircuitBreakVerify }}
# $endsnippet


# $snippet trip_circuit_breaker.sh syntax="bash" outputis="text"
$ kubectl -n istio-io-circuitbreaker exec {{ .inputTerminalFlag }} $FORTIO_POD -c fortio /usr/bin/fortio -- \
    load -c 3 -qps 0 -n 30 -loglevel warning http://httpbin:8000/get {{ .afterCircuitBreakVerify }}
# $endsnippet

# $snippet print_statistics_after_tripping.sh syntax="bash" outputis="text"
$ kubectl -n istio-io-circuitbreaker exec {{ .inputTerminalFlag }} $FORTIO_POD -c istio-proxy -- \
    pilot-agent request GET stats | grep httpbin | grep pending {{ .outputRedirectionCmd }}
# $verify
cluster.outbound|8000||httpbin.istio-io-circuitbreaker.svc.cluster.local.circuit_breakers.default.rq_pending_open: ?
cluster.outbound|8000||httpbin.istio-io-circuitbreaker.svc.cluster.local.circuit_breakers.high.rq_pending_open: ?
cluster.outbound|8000||httpbin.istio-io-circuitbreaker.svc.cluster.local.upstream_rq_pending_active: ?
cluster.outbound|8000||httpbin.istio-io-circuitbreaker.svc.cluster.local.upstream_rq_pending_failure_eject: ?
cluster.outbound|8000||httpbin.istio-io-circuitbreaker.svc.cluster.local.upstream_rq_pending_overflow: ?
cluster.outbound|8000||httpbin.istio-io-circuitbreaker.svc.cluster.local.upstream_rq_pending_total: ?
# $endsnippet
